package hh.enums;

import java.util.HashMap;
import java.util.Map;

@SuppressWarnings({"rawtypes", "unchecked"})
public interface BaseEnum {
    Object lock = new Object();
    Map<Class<? extends Enum>, Map<String, Enum>> nameToEnum = new HashMap<>(16);
    Map<Class<? extends Enum>, Map<Integer, Enum>> codeToEnum = new HashMap<>(16);

    default void init(Enum e) {
        synchronized (lock) {
            Map<Integer, Enum> codeMap = codeToEnum.get(this.getClass());
            if (codeMap == null) codeToEnum.put(e.getClass(), codeMap = new HashMap<>(16));

            Map<String, Enum> nameMap = nameToEnum.get(this.getClass());
            if (nameMap == null) nameToEnum.put(e.getClass(), nameMap = new HashMap<>(16));

            if (getCnName() == null) throw new RuntimeException("枚举 getName()不能为返回null：" + this);
            codeMap.put(getCode(), e);
            nameMap.put(getCnName(), e);
            System.out.println("注册 " + this.getClass().getName() + ": " + e.name());
        }
    }

    Integer getCode();

    String getCnName();

    String getEnName();

    String getDoc();


    Map<Class<? extends Enum>, EnumHolder> enums = new HashMap<>(16);

    static <T extends Enum<T>> T fromCode(Class<? extends Enum<T>> type, Integer code) {
        EnumHolder<?> enumHolder = getEnumHolder(type);;
        return enumHolder == null ? null : (T) enumHolder.codeToEnum.get(code);
    }

    static <T extends Enum<T>> T fromCnName(Class<? extends Enum<T>> type, String cnName) {
        EnumHolder<?> enumHolder = getEnumHolder(type);;
        return enumHolder == null ? null : (T) enumHolder.cnNameToEnum.get(cnName);
    }

    static <T extends Enum<T>> T fromEnName(Class<? extends Enum<T>> type, String enName) {
        EnumHolder<?> enumHolder = getEnumHolder(type);
        return enumHolder == null ? null : (T) enumHolder.enNameToEnum.get(enName);
    }

    static <T extends Enum<T>> EnumHolder<?> getEnumHolder(Class<? extends Enum<T>> type) {
        EnumHolder<?> enumHolder = enums.get(type);
        if (enumHolder == null) {
            synchronized (enums) {
                enumHolder = enums.get(type);
                if (enumHolder == null)
                    enums.put(type, enumHolder = new EnumHolder<>());
            }
        }
        return enumHolder;
    }

    class EnumHolder<T extends Enum<T>> {
        Map<String, Enum> cnNameToEnum = new HashMap<>(16);
        Map<String, Enum> enNameToEnum = new HashMap<>(16);
        Map<Integer, Enum> codeToEnum = new HashMap<>(16);
        Class<T> type;
    }
}



